# -*- coding: utf-8 -*-
__author__ = 'lztkdr'
__date__ = '2020/11/27 16:47'

"""
    生成器是一种特殊的迭代器，使用小括号类似的列表推导式
    1- 生成器，可以直接用来next(迭代器)
    2- 使用了yeild的函数叫做生成器函数
    3- 调用生成器函数才能产生生成器iterator
    4- 生成器内部实现了iter，next，抛出异常的方法
"""


def testGenerator():
	data1 = [x for x in range(100000)]
	data2 = (x for x in range(100000))

	print(type(data1))  # list
	print(type(data2))  # type = generator

	print(next(data2))
	print(next(data2))
	print(next(data2))


"""
    yield的作用：
    1- 将yield后面的值作为**返回值**给调用生成器的地方
    2- 把当前函数挂起，在下一次调用生成器的时候，从上一次结束的地方开始
"""


def hello():
	yield 1
	yield 2
	yield 3
	yield 4


def testYield():
	generator = hello()
	print(next(generator))
	print(next(generator))

	# 挂起继续执行
	print(next(generator))
	print(next(generator))


"""
    使用yeild的计算fib
    1- while循环中不使用return返回值，因为是returm的不会产生生成器
    2- yield在循环中挂起，生成器迭代的时候，会从此行继续执行代码，判断while
    3- 如果使用send唤醒的话，yield还有一个作用就是收数据
"""


def testFib2(num):
	index = 0

	num1 = 0
	num2 = 1

	while index < num:
		temp = num1
		num1, num2 = num2, (num1 + num2)
		index += 1
		# return temp
		extra = yield temp
		print("接收到了send发送的额外的数据:%s" % extra)


def double_number(number):
	while True:
		number *= 2
		number = yield number


"""
    第一次调用生成器必须使用next，之后才可以使用send发送额外的数据
    send和next的作用类似，都是恢复生成器的挂起，但是send唤醒的时候可以传入额外的数据
"""


def main():
	testGenerator()
	print('------------------------------------')
	print('testYield:')
	testYield()
	print('------------------------------------')
	generator = testFib2(10)
	print(next(generator))
	print(generator.send("这是给yield额外的数据"))
	print('------------------------------------')
	c = double_number(4)
	#  第一次调用生成器必须使用next，之后才可以使用send发送额外的数据
	#  send和next的作用类似，都是恢复生成器的挂起，但是send唤醒的时候可以传入额外的数据
	print(next(c))
	print(c.send(5))
	print(c.send(6))


if __name__ == '__main__':
	main()
